package de.bazinga.rotw.zombie;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jmex.game.state.GameStateManager;
import com.jmex.model.animation.JointController;

import de.bazinga.rotw.game.Game;
import de.bazinga.rotw.game.RotwGameState;
import de.bazinga.rotw.gameModes.CaptureTheZombie;
import de.bazinga.rotw.model.ModelCache;
import de.bazinga.rotw.network.BasicSyncManager;
import de.bazinga.rotw.network.Client;
import de.bazinga.rotw.network.Server;
import de.bazinga.rotw.network.message.ZombieInfoMessage;
import de.bazinga.rotw.person.OpponentList;
import de.bazinga.rotw.person.Person;
import de.bazinga.rotw.player.Player;
import de.bazinga.rotw.sound.Sound;

public class Zombie extends Node {
	private static final long serialVersionUID = 1L;

	private JointController controller = null;
	
	private ZombieController zombieController = null;
	
	private int zombieIndex = 0;
	
	private Waypoint startWaypoint = null;
	
	private long lastTimeSoundPlayed = 0;
	
	private boolean caught = false;

	public Zombie(Waypoint startPoint, int zombieIndex) {
		this.zombieIndex = zombieIndex;
		this.startWaypoint = startPoint;
		
		loadModel();
		
		this.setLocalTranslation(startWaypoint.getLocation());
		
		controller.setTimes(2, 20);
		controller.setActive(true);
		
		zombieController = new ZombieController(this, startPoint);
		this.addController(zombieController);
		zombieController.setActive(true);
	}
	
	protected void loadModel() {		
		// Load Model
		URL zombieUrl = null;
		try {
			if(zombieIndex == 0) zombieUrl = new File("player/zombie/").toURI().toURL();
			else zombieUrl = new File("player/dwarf/").toURI().toURL();
		} catch (MalformedURLException e1) {
			e1.printStackTrace();
		}

		Node zombie = null;
		if(zombieIndex == 0)
			zombie = ModelCache.getInstance().loadModel(zombieUrl, zombieUrl, "/player/zombie/zombie02.ms3d");
		else
			zombie = ModelCache.getInstance().loadModel(zombieUrl, zombieUrl, "/player/dwarf/dwarf1.ms3d");
		
        if(zombieIndex == 0) zombie.setLocalScale(0.14f);
        else zombie.setLocalScale(0.05f);
        
        Quaternion rot180 = new Quaternion();
        rot180.fromAngleAxis(135, Vector3f.UNIT_Y);
        if(zombieIndex == 1) zombie.setLocalRotation(rot180);
        
        this.attachChild(zombie);
        
        
        
        
        controller = (JointController)zombie.getController(0);
        controller.setRepeatType(Controller.RT_CYCLE);
        if(zombieIndex == 0) controller.setSpeed(1f);
        else controller.setSpeed(0.5f);
        controller.setActive(false);
	}
	
	
	
	public void reset() {
		this.setLocalTranslation(startWaypoint.getLocation());
		zombieController.setCurrentWaypoint(startWaypoint);
		zombieController.setActive(true);
		zombieController.setPersonToFollow(null);
		
		if(zombieIndex == 0) {
			controller.setTimes(2, 20);
			controller.setActive(true);
		}else{
			controller.setTimes(2, 14);
			controller.setActive(true);
		}

		caught = false;
		
		setCullHint(CullHint.Never);
	}
	
	
	public void collisionWithPlayer(Player player) {
		if((player.getTeam()-1) == getZombieIndex()) {
			// Same Team
			if(player.hasZombie()) {
				RotwGameState gameState = ((RotwGameState)GameStateManager.getInstance().getChild("gameState"));
				
				int otherZombieIndex = (getZombieIndex() == 0) ? 1:0;
				Zombie otherZombie = 
					((CaptureTheZombie)gameState.getGameMode()).getZombie(otherZombieIndex);
				// Do nothing if the Zombie is caught
				
				if(isCaught()) return ;
				
				player.setHasZombie(false);
				
				// Reset other Zombie
				otherZombie.reset();
				caught = false;
				
				// Add Score
				

				// Hide Zombie-Icon
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getHUD().hideZombie();
				
				if(player.getTeam() == 1) {
					RotwGameState.teamOneScore++;
				}else{
					RotwGameState.teamTwoScore++;
				}
				
				sendInfoMessage(ZombieInfoMessage.ZOMBIE_SCORED);
				
				if(Game.getGame().getSettings().isSFX()) {
					Sound.getInstance().getAudioTrack("sounds/scored.wav").play();
				}
				
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).addChatMessage("You Scored!");
			}
		}else{
			System.out.println("CAUGHT: "+getZombieIndex());
			if(caught) return ;
			caught = true;
			
			// Different Team -> Grap the Zombie!!
			setCullHint(CullHint.Always);
			setLocalTranslation(new Vector3f(999,-999,999));
			zombieController.setActive(false);
			
			player.setHasZombie(true);
			
			// Show Zombie-Icon
			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getHUD().showZombie();
			
			
			sendInfoMessage(ZombieInfoMessage.ZOMBIE_CAUGHT);
			

			if(Game.getGame().getSettings().isSFX() && (System.currentTimeMillis() - lastTimeSoundPlayed) > 1000) {
				Sound.getInstance().getAudioTrack("sounds/zombie.wav").play();
				lastTimeSoundPlayed = System.currentTimeMillis();
			}
			
			String name = (getZombieIndex() == 0) ? "Zombie":"Dwarf";
			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).addChatMessage("You stole the "+name+"!");
		}
	}
	
	
	public void sendInfoMessage(int flag) {
		ZombieInfoMessage zim = new ZombieInfoMessage();
		zim.setZombieIndex(getZombieIndex());
		zim.setZombieInfo(flag);
		
		BasicSyncManager syncManager = 
			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getSyncManager();
		if(syncManager instanceof Server) {
			((Server)syncManager).getServer().sendToAll(zim);
		}else{
			((Client)syncManager).getClient().sendToServer(zim);
		}
	}
	
	
	public void handleMessage(ZombieInfoMessage zim) {
		if(zim.getZombieInfo() == ZombieInfoMessage.ZOMBIE_CAUGHT) {
			caught = true;
			
			OpponentList.getInstance().getOpponent(zim.getPlayerId()).setHasZombie(true);
			zombieController.setPersonToFollow(OpponentList.getInstance().getOpponent(zim.getPlayerId()));
			
			//controller.setTimes(2, 14);
			//controller.setActive(true);
			
			String name = (getZombieIndex() == 0) ? "Zombie":"Dwarf";
			
			Player player = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPlayer();
			if(OpponentList.getInstance().getOpponent(zim.getPlayerId()).getTeam() != player.getTeam()) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).addChatMessage(OpponentList.getInstance().getOpponent(zim.getPlayerId()).getPlayerName()+" stole your "+name+"!");
			}else{
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).addChatMessage("Your Team stole the "+name+"!");
			}
			
		}else if(zim.getZombieInfo() == ZombieInfoMessage.ZOMBIE_LOST) {
			reset();
			caught = false;
			
			OpponentList.getInstance().getOpponent(zim.getPlayerId()).setHasZombie(false);
			
			String name = (getZombieIndex() == 0) ? "Zombie":"Dwarf";
			
			Player player = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPlayer();
			if(OpponentList.getInstance().getOpponent(zim.getPlayerId()).getTeam() != player.getTeam()) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).addChatMessage(OpponentList.getInstance().getOpponent(zim.getPlayerId()).getPlayerName()+" lost your "+name+"!");
			}else{
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).addChatMessage("Your Team lost the "+name+"!");
			}
		}else if(zim.getZombieInfo() == ZombieInfoMessage.ZOMBIE_SCORED) {
			OpponentList.getInstance().getOpponent(zim.getPlayerId()).setHasZombie(false);
			caught = false;
			
			if(OpponentList.getInstance().getOpponent(zim.getPlayerId()).getTeam() == Person.TEAM_ONE) {
				RotwGameState.teamOneScore++;
			}else{
				RotwGameState.teamTwoScore++;
			}
			
			// Reset other Zombie
			RotwGameState gameState = ((RotwGameState)GameStateManager.getInstance().getChild("gameState"));
			
			int otherZombieIndex = (getZombieIndex() == 0) ? 1:0;
			((CaptureTheZombie)gameState.getGameMode()).getZombie(otherZombieIndex).reset();
			
			
			// play sound
			if(Game.getGame().getSettings().isSFX()) {
				Sound.getInstance().getAudioTrack("sounds/scored.wav").play();
			}
			

			Player player = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPlayer();
			if(OpponentList.getInstance().getOpponent(zim.getPlayerId()).getTeam() != player.getTeam()) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).addChatMessage(OpponentList.getInstance().getOpponent(zim.getPlayerId()).getPlayerName()+" scored!");
			}else{
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).addChatMessage("Your Team scored!");
			}
		}
	}
	
	
	public ZombieController getZombieController() {
		return zombieController;
	}

	public int getZombieIndex() {
		return zombieIndex;
	}

	public void setZombieIndex(int zombieIndex) {
		this.zombieIndex = zombieIndex;
	}
	
	public void setStartWaypoint(Waypoint w) {
		this.startWaypoint = w;
		reset();
	}
	
	
	public boolean isCaught() {
		return caught;
	}

	public void setCaught(boolean caught) {
		this.caught = caught;
	}
}
